﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Flagwind.Resources;

namespace Flagwind.Security
{
	/// <summary>
	/// 签名相关
	/// </summary>
	public class Signature
	{
		#region 私有变量

		/// <summary>
		/// 参数字典
		/// </summary>
		private SortedDictionary<string, object> _parameters = new SortedDictionary<string, object>();

		#endregion

		#region 构造函数

		/// <summary>
		/// 构造函数
		/// </summary>
		public Signature()
		{

		}

		/// <summary>
		/// 构造函数
		/// </summary>
		public Signature(SortedDictionary<string, object> parameters)
		{
			_parameters = parameters;
		}

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="parameters"></param>
		/// <param name="partnerId"></param>
		/// <param name="timestamp"></param>
		public Signature(SortedDictionary<string, object> parameters, string partnerId, long timestamp)
		{
			_parameters = parameters;

			if(string.IsNullOrWhiteSpace(partnerId))
				throw new InvalidOperationException("合作者ID不能为空.");

			if(timestamp <= 0)
				throw new InvalidOperationException("时间戳不能小于0.");

			_parameters["partnerId"] = partnerId;
			_parameters["timestamp"] = timestamp;
		}

		#endregion

		#region 签名相关

		/// <summary>
		/// 生成签名，详见签名生成算法
		/// </summary>
		/// <returns>签名</returns>
		public string MakeSign()
		{
			//转url格式
			string url = ToUrl();

			//MD5加密
			var md5 = MD5.Create();
			var urlBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(url));

			var str = new StringBuilder();

			foreach(byte item in urlBytes)
			{
				str.Append(item.ToString("x2"));
			}

			//所有字符转为大写
			return str.ToString().ToUpper();
		}

		/// <summary>
		/// 检测签名是否正确
		/// </summary>
		/// <param name="sign"></param>
		/// <returns>正确返回true，错误返回false</returns>
		public bool CheckSign(string sign)
		{
			//在本地计算新的签名
			string makeSign = MakeSign();

			if(makeSign == sign.ToUpper())
				return true;
			else
				return false;
		}

		#endregion

		#region 私有

		private string ToUrl()
		{
			var str = new StringBuilder();

			foreach(KeyValuePair<string, object> pair in _parameters)
			{
				if(pair.Key.ToLower() != "sign" && pair.Value != null && pair.Value.ToString() != "")
					str.AppendFormat("{0}={1}&", pair.Key, pair.Value.ToString());
			}

			return str.ToString().Trim('&');
		}

		#endregion
	}
}
